/*-
 * VP.java          TP-Validity-Period (TP-VP)
 *
 * $LastChangedBy: stein $
 * $LastChangedRevision: 98 $
 * $LastChangedDate: 2007-02-20 15:18:26 +0000 (Tue, 20 Feb 2007) $
 * $HeadURL: svn://localhost/SMS/src/com/googlecode/attention/sms/pdu/VP.java $
 *
 * Copyright (c) 2007, Stein Gunnar Bakkeby
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Stein Gunnar Bakkeby nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.googlecode.attention.sms.pdu;

import com.googlecode.attention.util.KeepingReference;

/**
 * TP-Validity-Period (TP-VP).
 * <BR>Validity period specifies the time when SM expires. If SM is't
 * delivered before that moment, it is discarded by SC.
 * Validity-Period can be in three different formatS:<BR>
 * <LI>Relative, Absolute and Enhanced.</LI>
 * <BR>
 * <BR>
 * To make use of the field values, one must first check the validity period
 * format according to the field values. The format is usually retrieved from
 * the first octet of this SMS-SUBMIT or SMS-DELIVER.
 * <BR>
 * <BR><B>TP-VP (Relative format)</B>.
 * <BR>The TP-Validity-Period comprises 1 octet in integer representation,
 * giving the length of the validity period, counted from when the
 * SMS-SUBMIT is received by the SC.
 * <BR>
 * <BR>The representation of time is as follows:
 * <BR>TP-VP value Validity period value
 * <BR>0 to 143 (TP-VP + 1) x 5 minutes (i.e. 5 minutes intervals
 * up to 12 hours)
 * <BR>144 to 167 12 hours + ((TP-VP -143) x 30 minutes)
 * <BR>168 to 196 (TP-VP - 166) x 1 day
 * <BR>197 to 255 (TP-VP - 192) x 1 week
 * <BR>
 * <BR>
 * <BR><B>TP-VP (Absolute format)</B>.
 * <BR>The TP-Validity Period comprises 7 octets in semi octet
 * representation giving the absolute time of the validity period termination.
 * The representation of time is identical to the representation of the
 * TP-Service-Centre-Time-Stamp.
 * <BR>
 * <BR>
 * <BR><B>TP-VP (Enhanced format)</B>.
 * <BR>The TP-Validity Period comprises 7 octets. The presence of all
 * octets is mandatory although they may not all be used. The first
 * octet indicates the way in which the following 6 octets are used.
 * Any reserved/unused bits or octets must be set to zero.
 * <BR>
 * <BR>Octet 1 TP-VP functionality indicator
 * <BR>bit 7 Extension bit
 * <BR>Set to 1 if the TP-VP functionality indicator is to be extended
 * to another octet. A setting of 0 indicates that there are no more
 * TP-VP functionality indicator extension octets to follow. Any such
 * extension octet shall immediately follow the previous TP-VP
 * functionality indicator.
 * <BR>
 * <BR>bit 6 Single shot SM.
 * <BR>Set to 1 if the SC is required to make up to one delivery attempt.
 * The TP-Validity Period, where present, shall be applicable to the Single
 * shot SM.
 * <BR>
 * <BR>bits 5, 4, 3 Reserved
 * <BR>
 * <BR>bits 2, 1, 0 Validity Period Format.
 * <BR>Value bits 2 1 0
 * <BR>
 * <TABLE>
 * <TR><TD>0</TD><TD>0</TD><TD>0</TD><TD>No Validity Period specified</TD></TR>
 * <TR><TD>0</TD><TD>0</TD><TD>1</TD><TD>Validity Period is as specified for the relative case. The following octet contains the TPVP value</TD></TR>
 * <TR><TD>0</TD><TD>1</TD><TD>0</TD><TD>Validity period is relative in integer representation and the following octet contains the TP-VP value in the range 0 to 255 representing 0 to 255 seconds. A TP-VP value of zero is undefined and reserved for future use.</TD></TR>
 * <TR><TD>0</TD><TD>1</TD><TD>1</TD><TD>Validity period is relative in semi-octet representation. The following 3 octets contain the relative time in Hours, Minutes and Seconds giving the length of the validity period counted from when the SMS-SUBMIT is received by the SC. The representation of time uses the same representation as the Hours, Minutes and Seconds in the TP-Service-Centre-Time-Stamp.</TD></TR>
 * <TR><TD>1</TD><TD>0</TD><TD>0</TD><TD>Reserved</TD></TR>
 * <TR><TD>1</TD><TD>0</TD><TD>1</TD><TD>Reserved</TD></TR>
 * <TR><TD>1</TD><TD>1</TD><TD>0</TD><TD>Reserved</TD></TR>
 * <TR><TD>1</TD><TD>1</TD><TD>1</TD><TD>Reserved</TD></TR>
 * </TABLE>
 * <BR>
 * <BR>The SC shall reject any Unsupported/ Reserved values received by
 * returning the "TP-VP not supported" TP-FCS value in the Submit SM
 * Report for RP-Error.
 *
 * <BR><A HREF="http://www.dreamfabric.com/sms/vp.html">
 *              http://www.dreamfabric.com/sms/vp.html</A>
 *
 * @author Stein Gunnar Bakkeby
 */
public class VP {

  /* Field values */
  /** The VP octets. */
  protected int[] octets;
  protected VPF vpf;
  
  /**
   * Default constructor, creates an empty validity period.
   */
  public VP() {
    this.octets = new int[0];
    this.vpf    = VPF.FIELD_NOT_PRESENT;
  }
  
  /**
   * Constructor, takes octets representing the validity period.
   * <BR>
   * <BR>The validity period format can be retrieved from the first octet
   * of the SMS-SUBMIT.
   *
   * @param octets The octet(s) representing validity period of an SMS-SUBMIT
   * @param vpf The validity period format
   */
  @KeepingReference(ref="octets")
  public VP(final int[] octets, final VPF vpf) {
    this.octets = octets;
    this.vpf    = vpf;
  }
  
  /**
   * This will set the validity period.
   * <BR>
   * <BR>Note that this method will not check
   * whether the data corresponds to the validity period format defined in
   * the first octet of an SMS-DELIVER.
   * 
   * @param octets The octet(s) representing validity period of an SMS-SUBMIT
   */
  @KeepingReference(ref="octets")
  public void setVP(final int[] octets) {
    this.octets = octets;
  }
  
  /**
   * This will set the validity period format and reset the validity period
   * if the new format differs from the old format.
   * 
   * @param vpf The VPF
   */
  public void setVPF(final VPF vpf) {
    final VPF oldFormat = this.vpf;
    this.vpf = vpf;
    if (oldFormat != this.vpf) {
      switch (this.vpf) {
      case FIELD_NOT_PRESENT:
        octets = new int[0];
        break;
        
      case ABSOLUTE_FORMAT:
      case ENHANCED_FORMAT:
        octets = new int[7];
        break;
        
      case RELATIVE_FORMAT:
        octets = new int[1];
        break;
        
      default:
        break;
      }
    }
  }
  
  /**
   * This will return the VPF.
   * 
   * @return The Validity-Period-Format
   */
  public VPF getVPF() {
    return vpf;
  }
  
  /**
   * This will return the octets representing validity period for the
   * SMS-SUBMIT.
   * <BR>
   * <BR>Make sure that the data corresponds to the validity period format
   * defined in the first octet of the TPDU.
   * 
   * @return The validity period
   */
  public int[] getVPOctets() {
    return octets;
  }
  
  /**
   * This will return an object of VPEnhancedTime or throw an
   * IllegalStateException if the VP format does not correspond to
   * enhanced format.
   * 
   * @return The VPEnhancedTime object
   * @throws IllegalStateException If VPF does not indicate enhanced format
   */
  public VPEnhancedTime getEnhancedTime() throws IllegalStateException {
    if (vpf == VPF.ENHANCED_FORMAT) {
      return new VPEnhancedTime(octets, vpf);
    }
    throw new IllegalStateException("VP format is not Enhanced Time!");
  }
  
  /**
   * This will return an object of VPRelativeTime or throw an
   * IllegalStateException if the VP format does not correspond to
   * relative time.
   * 
   * @return The VPRelativeTime object
   * @throws IllegalStateException If VPF does not indicate relative time
   */
  public VPRelativeTime getRelativeTime() throws IllegalStateException {
    if (vpf == VPF.RELATIVE_FORMAT) {
      return new VPRelativeTime(octets[0], vpf);
    }
    throw new IllegalStateException("VP format is not Relative Time!");
  }

  /**
   * Returns a SCTS formatted time. TP-VP field is 7 octets long, containing
   * TP-SCTS formatted time when SM expires.
   *
   * @return An object of SCTS
   * @throws IllegalStateException If VPF does not indicate absolute time
   */
  public SCTS getAbsoluteTime() throws IllegalStateException {
    if (vpf == VPF.ABSOLUTE_FORMAT) {
      return new SCTS(octets);
    }
    throw new IllegalStateException("VP format is not Absolute Time!");
  }
  
  @Override
  public boolean equals(final Object another) {
    if (another instanceof VP) {
      final VP vp = (VP)another;
      final VPF vpf = vp.getVPF();
      if (this.vpf.value == vpf.value) {
        final int[] octets = vp.getVPOctets();
        final int length = octets.length;
        
        for (int i = 0; i < length; i++) {
          if (octets[i] != this.octets[i]) {
            return false;
          }
        }
        return true;
      }
    }
    return false;
  }
  
  /**
   * @return [VPF:&lt;vpf&gt;][&lt;vp&gt;]
   */
  public String toString() {
    final StringBuilder sb = new StringBuilder();
    sb.append("[VPF:");
    sb.append(vpf.toString());
    
    switch (vpf) {
    case RELATIVE_FORMAT:
      sb.append("][");
      sb.append(getRelativeTime().toString());
      break;
      
    case ABSOLUTE_FORMAT:
      sb.append("][");
      sb.append(getAbsoluteTime().toString());
      break;
      
    case ENHANCED_FORMAT:
      sb.append("][");
      sb.append(getEnhancedTime().toString());
      break;
      
    case FIELD_NOT_PRESENT: /* falls through */
    default:
      break;
    }
    sb.append(']'); // closes either vpf or vp
    return sb.toString();
  }
}